home *** CD-ROM | disk | FTP | other *** search
/ TeX 1995 July / TeX CD-ROM July 1995 (Disc 1)(Walnut Creek)(1995).ISO / biblio / bibtex / utils / refer-tools / refer2bibtex.pl-0.9.0 < prev    next >
Text File  |  1993-08-28  |  64KB  |  1,640 lines

  1. #!/usr/local/bin/perl
  2. #
  3. # r2b : convert a refer database to a BiBTeX database
  4. # Copyright 1992, 1993 by Dana Jacobsen (jacobsd@cs.orst.edu)
  5. #
  6. #version = "0.1.1";# 17 Apr 92  jacobsd  Wrote original version
  7. #version = "0.2.0";# 20 Apr 92  jacobsd  Added tib support
  8. #version = "0.3.0";# 21 Apr 92  jacobsd  Rewrote heuristics
  9. #version = "0.4.0";# 22 Apr 92  jacobsd  Revamped the rofftotex stuff
  10. #version = "0.5.2";# 24 Apr 92  jacobsd  some cleanup
  11. #version = "0.6.0";# 25 Apr 92  jacobsd  understands names
  12. #version = "0.6.1";# 26 Apr 92  jacobsd  cleanup
  13. #version = "0.6.2";# 27 Apr 92  jacobsd  added support for a few more fields
  14. #version = "0.6.3";# 27 Apr 92  jacobsd  little more tib support
  15. #version = "0.6.4";# 27 Apr 92  jacobsd  added Roman-8 chars and more options
  16. #version = "0.6.5";# 27 Apr 92  jacobsd  integrated error routine
  17. #version = "0.7.0";#  2 May 92  jacobsd  added groff chars and fixed bugs
  18. #version = "0.7.1";#  2 May 92  jacobsd  fixed a few more things
  19. #version = "0.7.2";# 10 Aug 92  jacobsd  changed key generation
  20. #version = "0.7.3";# 16 Aug 92  jacobsd  added ISBN, 2 overstrikes, -q
  21. #version = "0.7.4";# 19 Aug 92  jacobsd  overstrike, changes for proceedings
  22. #version = "0.7.5";# 20 Aug 92  jacobsd  efficiency moves, month abbrevs
  23. #version = "0.7.6";# 29 Aug 92  jacobsd  added eqn flag
  24. #version = "0.7.7";#  2 Sep 92  jacobsd  changed name, edition, report parsing
  25. #version = "0.8.0";#  4 Sep 92  jacobsd  added date and option field to header
  26. #version = "0.8.1";#  7 Sep 92  jacobsd  added ibm option, corrected ms macros
  27. #version = "0.8.2";#  5 Oct 92  jacobsd  fixed -ms/-mm macro confusion (again)
  28. #version = "0.8.3";#  5 Oct 92  jacobsd  parsedate, edition, movements
  29. #version = "0.8.4";#  8 Oct 92  jacobsd  added \s point size changing
  30. #version = "0.8.5";# 14 May 93  jacobsd  literals, parsename, font changing
  31. $version = "0.9.0";# 20 May 93  jacobsd  
  32. #
  33. # todo: final debugging for release
  34. #
  35. # All bug-fixes, suggestions, flames, and compliments gladly accepted.
  36. #
  37.  
  38. # These are site selected.
  39. #
  40. $maxflength = 2950;  # Bibtex doesn't want lines longer than this.
  41. $maxllength = 14;    # maximum length of the text in a label (plus decade)
  42. $prcontents = 0;     # print the contents (%Y) field.
  43.  
  44. # These are the program defaults that can be changed by command line options.
  45. #
  46. $roffconv   = 1;   # -n          : no roff-to-tex conversion
  47. $ibmconv    = 0;   # -ibm        : convert ibm graphics characters
  48. $nowarnings = 0;   # -q          : don't print warnings
  49. $tibfmt     = 0;   # -tib        : tib bibliography format
  50. $overstrike = 0;   # -overstrike : allow \:o = \(:o.  European troff??
  51. $handleeqn  = 0;   # -eqn        : handle some eqn @@ delimited constructs
  52. $ignorelabel= 0;   # -ignorelabel: don't use L field for citekey
  53. $deroffonly = 0;   # -deroff-only
  54. $protectTeX = 1;   # -noprotect  : don't protect TeX special characters
  55. $nameconv   = 1;   # -noname-conv
  56. $revauthor  = 0;   # -reverse-author
  57. $capprotect = 1;   # -nocap-protect = 0. -cap-protect = 2.
  58.  
  59. $convertcommand = '';
  60. $toterrors = 0;
  61.  
  62. while (@ARGV) {
  63.   $_ = shift @ARGV;
  64.   $convertcommand .= ' ' . $_;
  65.   /^--$/  && do { push(@files, @ARGV); undef @ARGV; next; };
  66.   /^-n$/  && do { $roffconv = 0;    next; };
  67.   /^-ibm/ && do { $ibmconv = 1;     next; };
  68.   /^-q$/  && do { $nowarnings = 1;  next; };
  69.   /^-qq$/ && do { $nowarnings = 2;  next; };   # this turns off ALL messages
  70.   /^-tib/ && do { $tibfmt = 1;      next; };
  71.   /^-ove/ && do { $overstrike = 1;  next; };
  72.   /^-eqn/ && do { $handleeqn = 1;   next; };
  73.   /^-der/ && do { $deroffonly = 1;  next; };
  74.   /^-non/ && do { $nameconv = 0;    next; };
  75.   /^-rev/ && do { $revauthor = 1;   next; };
  76.   /^-noc/ && do { $capprotect = 0;  next; };
  77.   /^-cap/ && do { $capprotect = 2;  next; };
  78.   /^-ign/ && do { $ignorelabel = 1; next; };
  79.   /^-nop/ && do { $protectTeX = 0;  next; };
  80.   push (@files, $_);
  81. }
  82.  
  83. if ($#files == -1) {
  84.   push (@files, "-");
  85. }
  86.  
  87. print "%\n";
  88. print "% converted from ", ($tibfmt ? "tib" : "refer");
  89. print " format by refer-to-bibtex $version";
  90. @tarr = localtime(time);
  91. # convert month from numeric to textual
  92. $tarrmon = (Jan, Feb, Mar, Apr, May, Jun, Jul, Aug,
  93.             Sep, Oct, Nov, Dec)[$tarr[4]];
  94. # add a leading 0 if the minute is only 1 digit.
  95. $tarr[1] = '0' . $tarr[1] if length($tarr[1]) == 1;
  96. # print date in format "21:09, 4 Sep 92"
  97. print " -- $tarr[2]:$tarr[1], $tarr[3] $tarrmon $tarr[5]\n";
  98. # print the command line as they entered it, so we know special options
  99. print "% r2b$convertcommand\n";
  100. print "%\n\n";
  101.  
  102. foreach $infile (@files) {
  103.  open (IN, $infile) || ((warn "Can't open $infile: $!\n"), next);
  104.  $linenum    = 0;
  105.  $lastfield  = 0;
  106.  $errors     = 0;
  107.  
  108.  if ($deroffonly) {
  109.    while (<IN>) {
  110.      chop;
  111.      $linenum++;
  112.      $_ = &doibmtoroff($_) if $ibmconv;
  113.      $_ = &dorofftotex($_) if $roffconv;
  114.      print $_, "\n";
  115.    }
  116.    exit 0;
  117.  }
  118.  
  119.  while (<IN>) {
  120.   chop;
  121.   $linenum++;
  122.  
  123.   /^\s*$/ && do { if ($lastfield) {
  124.                     &doentry();
  125.                     undef(%entry);
  126.                     undef($lastfield);
  127.                   }
  128.                   next;
  129.                 };
  130.  
  131.   /^[^%]/ && do { if ($lastfield) {
  132.                     if ( ($lastfield eq X) || ($lastfield eq Y) ) {
  133.                       $entry{$lastfield} .= "\n" . $_;
  134.                     } else {
  135.                       $entry{$lastfield} .= " " . $_;
  136.                     }
  137.                   } else {
  138.                     print STDERR "line $linenum:";
  139.                     print STDERR "Line without field identifier: \n$_\n";
  140.                     $errors++;
  141.                   }
  142.                   next;
  143.                 };
  144.  
  145.   $lastfield = 0;
  146.   if (substr($_, 3, 1) eq '#')   { next; }     # comment
  147.   $field = substr($_, 1, 1);
  148.  
  149.   #   Convert some lowercase fields to O.  Bibtex really doesn't have
  150.   # any way of dealing with tib's lower case ``translated'' fields.
  151.   #   Most of the lower case fields in my experience are usually typos.
  152.   #   Abstracts, contents, and comments seem to be non-standard.  I have 
  153.   # assumed %X for abstract and %Y for contents.
  154.   #   Refer, tib, and bib seem to have their own styles, and usually
  155.   # people add on fields anyway.  This is reaching the limits of what I
  156.   # can handle even by hand-translating.
  157.  
  158.   ($field =~ /^[or]$/) && do { $field = "O"; };
  159.  
  160.   $lastfield = $field;
  161.   if ($field eq '%')             { next; }     # comment
  162.   $rest = substr($_, 3);
  163.  
  164.   if ($field eq "\\") {
  165.     print q/@preamble{ "/, substr($_, 1), qq/" }\n/;
  166.     next;
  167.   }
  168.  
  169.   if ( ($field eq A) || ($field eq Q) || ($field eq E) ) {
  170.     $entry{$field} .= " and " . $rest;
  171.   } elsif ( ($field eq X) ) {
  172.     $entry{$field} .= "\n\n" . $rest;
  173.   } else {
  174.     $entry{$field} .= " " . $rest;
  175.   }
  176.  
  177.   # let 0 be a valid identifier, but we ignore it.  EndNote Plus puts it
  178.   # out as a type identifier, but it's often wrong.  We'll figure it out.
  179.  
  180. #  $allindents = "ABCDEGHIJKLMNOPQRSTUVXYZ0l*$";
  181. #  organize these in likelihood order and get some speed improvement.
  182. #  A: 21%, DT: 11.3%, P: 10%, K: 8.7%, V: 7.1%, J: 6.3%, ICB: 4.0%
  183.   $allindents = "ADTPKVJICBNESL0XRO*HGYMQUZl$";
  184.   if (index($allindents, $field) == -1) {
  185.     &anerror("Unknown field identifier: $_");
  186.   }
  187.  }
  188.  
  189.  if (%entry) {
  190.   &doentry();
  191.  }
  192.  
  193.  foreach $type (sort keys(%number)) {
  194.   ($nowarnings < 2) && printf STDERR "%5d %s\n", $number{$type}, $type;
  195.   $totalentries += $number{$type};
  196.  }
  197.  
  198.  if ($nowarnings < 2) {
  199.    print STDERR "$totalentries entries, ";
  200.    $errors == 0 ? print STDERR "no error" : print STDERR "$errors error";
  201.    $errors == 1 ? print STDERR "\n" : print STDERR "s\n";
  202.  }
  203.  $toterrors += $errors;
  204. }
  205.  
  206. exit $toterrors;
  207.  
  208.  
  209.  
  210.  
  211. ##########################################
  212. #
  213. sub doentry {
  214.  
  215. # do some processing on each field
  216.  
  217.   foreach $field (keys(%entry)) {
  218.     $entry{$field} =~ s/^\s+//;
  219.     $entry{$field} =~ s/\s+$//;
  220.  
  221.     $entry{$field} = &doibmtoroff($entry{$field}) if $ibmconv;
  222.     $entry{$field} = &dorofftotex($entry{$field}) if $roffconv;;
  223.  
  224.     if (length($entry{$field}) > $maxflength) {
  225.       $entry{$field} = substr($entry{$field}, 0, $maxflength-3);
  226.       $entry{$field} .= "...";
  227.       &anerror("field %$field longer than $maxflength characters.");
  228.     }
  229.     #$entry{$field} =~ s/(^|[^\\])~/$1\\ /g;  # ties (~) to literal space (\ )
  230.   }
  231.  
  232.  
  233. # Because the refer format does not have fields set aside for such things
  234. # as edition, ISBN, ISSN, look for them in other fields.  Also, some people
  235. # often put things like pages, techreport, and other information in the
  236. # wrong field.  Once again, look for them and move them to the correct one.
  237.  
  238.   #   Look for Thesis or Dissertation in O and move to R
  239.   if ($entry{O}) {
  240.     $_ = $entry{O};
  241.     if ( (!$entry{R}) && ( (/thesis/i) || /dissert/i) ) {
  242.       $entry{R} = $entry{O};
  243.       delete $entry{O};
  244.     }
  245.   }
  246.  
  247.   # Look for "Tech* Rep*" in S and move to R
  248.   if ( ($entry{S} =~ /tech\w*\s+rep\w*/i) && (!$entry{R}) ) {
  249.     $entry{R} = $entry{S};
  250.     delete $entry{S};
  251.   }
  252.  
  253.   # Look for "* No. *" in V and move to N
  254.   if (($entry{V} =~ /(\d+)\s+(no\.?|numb?e?r?\.?)\s+(\d+)/i) && (!$entry{N})){
  255.     $entry{N} = $3;
  256.     $entry{V} =~ s/(\d+)\s+(no\.?|numb?e?r?\.?)\s+(\d+)/$1/i;
  257.   }
  258.  
  259.   # Look for "* Edition" in some fields and move to Ed field
  260.   foreach $field (O,R,S,V,T,B) {
  261.     if ($entry{$field} =~ /([\w\d]+)\s+edition/i) {
  262.       $entry{Ed} = $1;
  263.       $entry{$field} =~ s/\s*[-,;(]?\s*([\w\d]+)\s+edition\s*[),;]?\s*//i;
  264.       if ($entry{$field} =~ /^\s*$/) {
  265.         delete $entry{$field};
  266.       }
  267.     }
  268.   }
  269.  
  270.   #   Look for ISBN/ISSN # in some fields and move to ISBN/ISSN
  271.   foreach $field (G,O) {
  272.     if ($entry{$field} =~ /IS[BS]N/) {
  273.       $entry{$field} =~ s/\\ /~/g;
  274.       if ($entry{$field} =~ /ISBN\s*:?\s*(\d\S*)/i) {
  275.         $entry{ISBN} = $1;
  276.         $entry{ISBN} =~ s/[;.,]$//g;
  277.         $entry{ISBN} =~ s/~/-/g;
  278.         $entry{$field} =~ s/\s*[,;]?\s*ISBN\s*:?\s*(\d\S*)\s*[,;]?//i;
  279.       }
  280.       if ($entry{$field} =~ /ISSN\s*:?\s*(\d\S*)/i) {
  281.         $entry{ISSN} = $1;
  282.         $entry{ISSN} =~ s/[;.,]$//g;
  283.         $entry{ISSN} =~ s/~/-/g;
  284.         $entry{$field} =~ s/\s*[,;]?\s*ISSN\s*:?\s*(\d\S*)\s*[,;]?//i;
  285.       }
  286.       $entry{$field} =~ s/(^|[^\\])~/$1\\ /g;
  287.     }
  288.   }
  289.  
  290.   # look for pp or pages in O and move to P
  291.   if ( (!$entry{P}) && ($entry{O} =~ /[XIVxiv]*\+?(\d+)\s*(pp\.?|pages),?/i) ) {
  292.     $entry{P} = $1;
  293.     $entry{O} =~ s/\s*[,;]?\s*[XIVxiv]*\+?(\d+)\s*(pp\.?|pages),?\s*//i;
  294.   }
  295.  
  296.   # look for date in B if there is no D field
  297.   if ( (!$entry{D}) && ($entry{B}) ) {
  298.     if ($entry{B} =~ /\b(\d\d\d\d)\b/) {
  299.       $entry{D} = $1;
  300.     } elsif ($entry{B} =~ /'(\d\d)\b/) {
  301.       $entry{D} = $1;
  302.     }
  303.   }
  304.  
  305.   # pick out reptype and repnumber
  306.   undef ($reptype, $repnumber);
  307.   if ($entry{R}) {
  308.     ($reptype, $repnumber) = $entry{R} =~ /(.+)\s+(\S+)$/;
  309.     if ($repnumber !~ /\d/) {
  310.       $reptype = $entry{R};
  311.       undef $repnumber;
  312.     }
  313.   }
  314.  
  315. # titles:  cap-protect = 0, leave them alone.
  316. #          cap-protect = 1, protect multi-cap sequences, and singles. (default)
  317. #          cap-protect = 2, protect all capitals.
  318.   if ($entry{T}) {
  319.     if ($capprotect == 1) {
  320.       1 while $entry{T} =~ 
  321.                s/([^{\\\w]|^)([A-Z]+)([^{}\\\w]|$)/$1{$2}$3/g;
  322.       $entry{T} =~ s/^{([A-Z])}/$1/;
  323.     } elsif ($capprotect == 2) {
  324.       $entry{T} =~ s/([A-Z]+)/{$1}/g;
  325.     }
  326.   }
  327.  
  328.   # set date fields
  329.  
  330.   &parsedate();
  331.  
  332.   # convert names to BiBTeX format as best we can
  333.   if ($entry{A}) {
  334.     $entry{Key_A} = &parsename($entry{A}, A);
  335.     $entry{A} = $fname;
  336.     $aeditors = $editors;
  337.     $acauthor = $corpauthors;
  338.   }
  339.   if ($entry{E}) {
  340.     $entry{Key_E} = &parsename($entry{E}, E);
  341.     $entry{E} = $fname;
  342.   } elsif ($aeditors) {
  343.     $entry{E}     = $entry{A};
  344.     $entry{Key_E} = $entry{Key_A};
  345.     delete $entry{Key_A};
  346.     delete $entry{A};
  347.   }
  348.   if ($entry{Q} || $entry{I}) {
  349.     if ($entry{Q}) {
  350.       $entry{Q} =~ s/^and //;
  351.       $entry{Q} =~ s/\s+/ /g;
  352.       ($entry{Key_Q}) = split(/[\s~]/, $entry{Q});
  353.     } else {
  354.       ($entry{Key_I}) = split(/[\s~]/, $entry{I});
  355.     }
  356.     if ($acauthor) {
  357.       ($entry{Key_A}) = split(/[\s~]/, $entry{A});
  358.       $entry{Key_A} =~ s/^{([^}]*)}?.*$/$1/;
  359.     }
  360.   } elsif ($acauthor) {
  361.     $entry{Q}     = $entry{A};
  362.     ($entry{Key_Q}) = split(/[\s~]/, $entry{Q});
  363.     $entry{Key_Q} =~ s/^{([^}]*)}?.*$/$1/;
  364.     delete $entry{Key_A};
  365.     delete $entry{A};
  366.   }
  367.  
  368.   # set or generate key
  369.   &genkey();
  370.  
  371.   # determine the Entry Type
  372.   # This is where the heuristics come into play.  We need to examine what
  373.   # fields we were given, and sometimes examine the field contents, to
  374.   # determine what type of entry this is.
  375.  
  376.   if ($entry{J} && !$entry{B}) {
  377.     $type = 'article';
  378.     $_ = $entry{J};
  379.     if (/^proc\w*\.\s/i || /proceeding/i || /proc[.]?\s+of\s/i ||
  380.         /conference/i || /symposium/i || /workshop/i ) {
  381.       $type = 'inproceedings';
  382.       $entry{B} = $entry{J};
  383.       if ($entry{N}) {   # These should be %B Proc, %J Journal, but do anyway.
  384.         # Hope they did "proceedings of ..., published as ..."
  385.         if (/^(.*)published\s+(in|as)\s+(.*)$/i) {
  386.           $entry{B} = $1;
  387.           $entry{J} = $3;
  388.           $entry{B} =~ s/,?\s*$//;
  389.         }
  390.         $entry{O} .= "Published as $entry{J}";
  391.         if ($entry{V}) { $entry{O} .= ", volume $entry{V}"; }
  392.         if ($entry{N}) { $entry{O} .= ", number $entry{N}"; }
  393.         delete $entry{V};
  394.         delete $entry{N};
  395.       }
  396.       delete $entry{J};
  397.     }
  398.   } elsif ($entry{B}) {
  399.     $type = '';
  400.     if ($entry{T}) {
  401.       $type .= 'in';
  402.     }
  403.     $_ = $entry{B};
  404.     if (/^proc\w*\.\s/i || /proceeding/i || /conference/i || /workshop/i) {
  405.       $type .= 'proceedings';
  406.     } else {
  407.       $type .= 'collection';
  408.     }
  409.     if ($entry{J}) {
  410.       $entry{O} .= "Published as $entry{J}";
  411.       if ($entry{V}) { $entry{O} .= ", volume $entry{V}"; }
  412.       if ($entry{N}) { $entry{O} .= ", number $entry{N}"; }
  413.       delete $entry{J};
  414.       delete $entry{V};
  415.       delete $entry{N};
  416.     }
  417.   } elsif ($entry{R}) {
  418.     $type = 'techreport';
  419.     $_ = $reptype;
  420.     s/^{\\[rbi][mft] //g;       # just in case someone changed the font
  421.     tr/A-Za-z//cd;              # only A-z are left
  422.     if (/^phd/i) {
  423.       $type = 'phdthesis';
  424.       $reptype = "Ph.{D}. Thesis";
  425.     }
  426.     if (/^diploma/i) {
  427.       $type = 'phdthesis';
  428.       $reptype = "Diploma Thesis";
  429.     }
  430.     if (/^master/i || /^m[as]thes/i) {
  431.       $type = 'mastersthesis';
  432.       $reptype = "Master's Thesis";
  433.     }
  434.     if (/^phd/i || /^master/i || /^m[as]thes/i || /^diploma/i) {
  435.       if ($entry{R} =~ /thesis/i) {
  436.         ($repnumber) = $entry{R} =~ /thesis\W*(.*)$/i;
  437.       }
  438.       if ($entry{R} =~ /dissert/i) {
  439.         $reptype =~ s/Thesis/Dissertation/;
  440.         ($repnumber) = $entry{R} =~ /dissert\w*\W*(.*)$/i;
  441.       }
  442.     }
  443.     /^draft/i     && ($type = 'unpublished');
  444.     /^unpublish/i && ($type = 'unpublished');
  445.  
  446.     if (!$entry{N}) {
  447.       $entry{N} = $repnumber;
  448.     }
  449.     $entry{Type} = $reptype;
  450.     undef $reptype;
  451.     undef $repnumber;
  452.     if ( (!$entry{Q}) && ($entry{I}) ) {
  453.       $entry{Q} = $entry{I};
  454.       delete $entry{I};
  455.     }
  456.   } elsif ($entry{I}) {
  457.     $type = 'book';
  458.   } else {
  459.     $type = 'misc';
  460.   }
  461.  
  462.   # BibTeX has no collection type, sigh.  We change 'collection' to 'book'.
  463.   if ($type eq 'collection') {
  464.     $type = 'book';
  465.   }
  466.  
  467.   $number{$type}++;
  468.   
  469.   # if we have an institution but no author, the Inst. is the author
  470.   if ( ($entry{Q}) && (!$entry{A}) ) {
  471.     $entry{A} = "{" . $entry{Q} . "}";
  472.   }
  473.  
  474.   # if there is no address, but a "header" field, assume H stands for "held in"
  475.   if ( ($entry{H}) && (!$entry{C}) ) {
  476.     $entry{C} = $entry{H};
  477.     delete $entry{H};
  478.   }
  479.   # set institution to be the corporate author unless it's Anonymous
  480.   if ($entry{Q} !~ /^anon\.?\w*$/i) {
  481.     $entry{Ins} = $entry{Q};
  482.   }
  483.   # if we have a reptype and number, but no "Type" entry, move to other.
  484.   if ($reptype) {
  485.     $entry{O} .= $entry{R};
  486.     delete $entry{R};
  487.   }
  488.  
  489.  
  490.   # Change things around for each types
  491.   $_ = $type;
  492.  
  493.   /^mastersthesis/ && do { $entry{Sch} = $entry{Ins}; delete $entry{Ins}; };
  494.   /^phdthesis/     && do { $entry{Sch} = $entry{Ins}; delete $entry{Ins}; };
  495.   /^unpublished/   && do { $entry{O} .= $entry{Ins}; delete $entry{Ins}; };
  496.  
  497.   # Syntax checking
  498.  
  499.   /^article/       && (&syntax(A, T, J, Yr));
  500.   /^book/          && (&syntax(AE, T, I, Yr));
  501.   /^incollection/  && (&syntax(A, T, B, I, Yr));
  502.   /^inproceedings/ && (&syntax(A, T, B, Yr));
  503.   /^mastersthesis/ && (&syntax(A, T, Sch, Yr));
  504.   /^phdthesis/     && (&syntax(A, T, Sch, Yr));
  505.   /^proceedings/   && (&syntax(BT, Yr));
  506.   /^techreport/    && (&syntax(A, T, Ins, Yr));
  507.   /^unpublished/   && (&syntax(A, T, O));
  508.  
  509.   # set up the entry output string
  510.  
  511.   $ent = '';
  512.   $ent .= "@$type\{$key,\n";
  513.  
  514.   if ($entry{Key}) { $ent .= "   key = \{$entry{Key}\},\n"; }
  515.   if ($entry{A})   { $ent .= "   author = \{$entry{A}\},\n"; }
  516.   if ($entry{E})   { $ent .= "   editor = \{$entry{E}\},\n"; }
  517.   if ($entry{T})   { $ent .= "   title = \{$entry{T}\},\n"; }
  518.   if ($entry{B})   {
  519.     if ($entry{T}) {
  520.                      $ent .= "   booktitle = \{$entry{B}\},\n";
  521.     } else {
  522.                      $ent .= "   title = \{$entry{B}\},\n";
  523.     } }
  524.   if ($entry{Ins}) { $ent .= "   institution = \{$entry{Ins}\},\n"; }
  525.   if ($entry{Sch}) { $ent .= "   school = \{$entry{Sch}\},\n"; }
  526.   if ($entry{J})   { $ent .= "   journal = \{$entry{J}\},\n"; }
  527.   if ($entry{Type}){ $ent .= "   type = \{$entry{Type}\},\n"; }
  528.   if ($entry{S})   { $ent .= "   series = \{$entry{S}\},\n"; }
  529.   if ($entry{V})   { $ent .= "   volume = \{$entry{V}\},\n"; }
  530.   if ($entry{N})   { $ent .= "   number = \{$entry{N}\},\n"; }
  531.   if ($entry{Ed})  { $ent .= "   edition = \{$entry{Ed}\},\n"; }
  532.   if ($entry{P})   { $ent .= "   pages = \{$entry{P}\},\n"; }
  533.   if ($entry{I})   { $ent .= "   publisher = \{$entry{I}\},\n"; }
  534.   if ($entry{C})   { $ent .= "   address = \{$entry{C}\},\n"; }
  535.   # since we allow abbrevs for month, don't print {}s
  536.   if ($entry{Mo})  { $ent .= "   month = $entry{Mo},\n"; }
  537.   if ($entry{Yr})  { $ent .= "   year = \{$entry{Yr}\},\n"; }
  538.   if ($entry{'$'}) { $ent .= "   price = \{$entry{'$'}\},\n"; }
  539.   if ($entry{'*'}) { $ent .= "   copyright = \{$entry{'*'}\},\n"; }
  540.   if ($entry{K})   { $ent .= "   keywords = \{$entry{K}\},\n"; }
  541.   if ($entry{M})   { $ent .= "   mrnumber = \{$entry{M}\},\n"; }
  542.   if ($entry{l})   { $ent .= "   language = \{$entry{l}\},\n"; }
  543.   if ($entry{U})   { $ent .= "   annote = \{$entry{U}\},\n"; }
  544.   if ($entry{ISBN}){ $ent .= "   ISBN = \{$entry{ISBN}\},\n"; }
  545.   if ($entry{ISSN}){ $ent .= "   ISSN = \{$entry{ISSN}\},\n"; }
  546.   if ($entry{X})   { $ent .= "   abstract = \{$entry{X}\},\n"; }
  547.   if ($entry{G})   { $ent .= "   note = \{$entry{G}\},\n"; }
  548.   if ($entry{H})   { $ent .= "   note = \{$entry{H}\},\n"; }
  549.   if ($entry{O})   { $ent .= "   note = \{$entry{O}\},\n"; }
  550.   if ($entry{Z})   { $ent .= "   note = \{$entry{Z}\},\n"; }
  551.   if ($entry{Y})   { if (!$prcontents) { $entry{Y} = "(not listed)"; }
  552.                      $ent .= "   contents = \{$entry{Y}\},\n"; }
  553.  
  554.   substr($ent, -2, 1) = '';
  555.   $ent .= "\}\n\n";
  556.  
  557.   &printerrors();
  558.   print $ent;
  559. }
  560.  
  561. ##########################################
  562. #
  563. # date looks like                   month                dec  year           
  564. # --------------------------------  -------------------  --  ---------------
  565. # 1984                                                   84  1984           
  566. # 1974-1975                                              74  1974-1975      
  567. # August 1984                       aug                  84  1984           
  568. # May 1984 May 1984                 may                  84  1984           
  569. # 1976 November                     nov                  76  1976           
  570. # 1976 November 1976                nov                  76  1976           
  571. # 21 August 1984                    {21 August}          84  1984           
  572. # August 18-21, 1984                {August 18-21}       84  1984           
  573. # 18-21 August 1991                 {18-21 August}       91  1991           
  574. # July 31-August 4, 1984 1984       {July 31-August 4}   84  1984           
  575. # July-August 1980                  {July-August}        80  1980           
  576. # February 1984 (revised May 1991)  feb                  84  1984           
  577. # Winter 1990                       {Winter}             90  1990           
  578. # 1988 (in press)                                        88  1988 (in press)
  579. # to appear                                              ??  to appear
  580. #
  581. sub parsedate {
  582.   local($date) = $entry{D};
  583.  
  584. # These were done earlier for each field
  585. #  $date =~ s/^\s+//;
  586. #  $date =~ s/\s+$//;
  587.   $date =~ s/(\S+)\s+(\d+)\s+\1\s+\2/$1 $2/;   # handle duplicate dates
  588.   $date =~ s/^\s*(\d\d\d+)\s+(\S+)/$2 $1/;     # handle 1976 November
  589.   while ($date =~ /\s*[(]?((\d\d\d\d[-\/])?\d\d\d\d)[).]?\s*(\(.*\))?$/) {
  590.     $entry{Yr} = $1;
  591.     $date =~ s/,?\s*[(]?(\d\d\d\d[-\/])?\d\d\d\d[).]?\s*(\(.*\))?$//;
  592.   }
  593. #  $entry{YrKey} = $entry{Yr} ? $entry{Yr} : "????";
  594.   if ($entry{Yr}) {
  595.     $entry{YrKey} = $entry{Yr};
  596.   } elsif ($date =~ /(\d\d\d\d)/) {
  597.     $entry{YrKey} = $1;
  598.   } else {
  599.     $entry{YrKey} = "????";
  600.   }
  601.   $entry{Decade} = substr($entry{YrKey}, 2, 2);
  602.   if (length($date) == 0) { return; }
  603.  
  604.   $_ = $date;
  605.   if (!/[-\d]/) {
  606.     /^jan/i && do { $entry{Mo} = "jan"; };
  607.     /^feb/i && do { $entry{Mo} = "feb"; };
  608.     /^mar/i && do { $entry{Mo} = "mar"; };
  609.     /^apr/i && do { $entry{Mo} = "apr"; };
  610.     /^may/i && do { $entry{Mo} = "may"; };
  611.     /^jun/i && do { $entry{Mo} = "jun"; };
  612.     /^jul/i && do { $entry{Mo} = "jul"; };
  613.     /^aug/i && do { $entry{Mo} = "aug"; };
  614.     /^sep/i && do { $entry{Mo} = "sep"; };
  615.     /^oct/i && do { $entry{Mo} = "oct"; };
  616.     /^nov/i && do { $entry{Mo} = "nov"; };
  617.     /^dec/i && do { $entry{Mo} = "dec"; };
  618.   }
  619.  
  620.   if (!$entry{Mo}) {
  621.     if (!$entry{Yr}) {
  622.       $entry{Yr} = $entry{D};
  623.     }
  624.     else {
  625.       $entry{Mo} = '{' . $date . '}';
  626.     }
  627.   }
  628.   $entry{Decade} = substr($entry{YrKey}, 2, 2);
  629. }
  630.  
  631. ##########################################
  632. # key is Author's last name followed by last 2 digits of year.
  633. # in corporate author's case, key is first word and first 2 digits.
  634. # order is L, A, Q, E, I, "Anonymous"
  635. # In case of conflict, ascending letters are added to the end
  636. # Perl knows that "z"+1 == "aa" and "az"+1 == "ba".  Uskomatonta!
  637. #
  638. # BiBTeX's cite keys are case-INsensitive.  We want to keep the
  639. # pretty looking capitalization though, so we modify key and lkey.
  640. # We now check Label fields for duplicate keys
  641. sub genkey {
  642.   local($noadd) = @_;
  643.   local($name, $lenkey);
  644.  
  645.   if ($entry{L} && (!$ignorelabel) ) {
  646.     $key = $entry{L};
  647.   } else {
  648.     $name = $entry{Key_A} || $entry{Key_Q} || $entry{Key_E}
  649.             || $entry{Key_I} || $noadd || "Anonymous";
  650.  
  651.     $name = sprintf("%.${maxllength}s", $name);
  652.     $key = $name . $entry{Decade};
  653.   }
  654.  
  655.   $key =~ s/,//g;
  656.   $lenkey = length($key);
  657.   $lkey = $key;
  658.   $lkey =~ tr/A-Z/a-z/;         # citekeys are case-insensitive
  659.  
  660.   if ($allkeys{$lkey}) {
  661.     $key .= 'a';
  662.     $lkey = $key;
  663.     $lkey =~ tr/A-Z/a-z/;
  664.     while ($allkeys{$lkey}) {
  665.       substr($key,$lenkey)++;   # increment all chars past Decade
  666.       $lkey = $key;
  667.       $lkey =~ tr/A-Z/a-z/;
  668.     }
  669.   }
  670.  
  671.   if ($noadd) {
  672.     return($key);
  673.   }
  674.  
  675.   $allkeys{$lkey} = $key;
  676.   if ($name eq "Anonymous") {
  677.     $entry{Key} = $key;
  678.   }
  679. }
  680.  
  681.  
  682. ##########################################
  683. # parsename parses names into BiBTeX format
  684. #
  685. # This uses heuristics to parse a name into First, von, Last, and Jr
  686. # parts.  It handles multiple names (John doe, jane doe) on a line.
  687. # It does not handle names in "last, first" format.
  688. # it returns a key (last name of author or editor, first name of corp).
  689. # It sets $fname to the full bibtex name.
  690. # It sets $editors, $authors, or $corpauthors if it thinks the name is one.
  691. #
  692. sub parsename {
  693.   local($allnames, $ntype) = @_;
  694.   local($firstn, $vonn, $lastn, $jrn);
  695.   local(@names, $keyn, $oname, $nname, $rest);
  696.  
  697.   undef $fname;
  698.   $editors = $authors = $corpauthors = 0;
  699.  
  700.   # handle unpaddable spaces (\ ) in names as if they were ties (\0)
  701.   $allnames =~ s/\\ /~/g;     # the ties (~) get converted back later.
  702.   $allnames =~ s/\s+/ /g;
  703.   $allnames =~ s/^and //;
  704.   $allnames =~ s/^and$//;
  705.  
  706.   if ( ($allnames !~ /\s/) && ($allnames !~ /anonymous/i) ){
  707.     $corpauthors = 1;
  708.   }
  709.   @names = split(/ and /, $allnames);
  710.   if (!$nameconv) {
  711.     $fname = $allnames;
  712.     $_ = shift @names;
  713.     # if we're leaving names alone, they're probably already in "Last, First"
  714.     # format, so use the first part of the name as the key.
  715.     ($name) = /^\s*(\S*)/;
  716.     #  ($name) = /(\S*)\s*$/;
  717.     $name =~ tr/A-Za-z0-9\/\-//cd;
  718.     return $name;
  719.   }
  720.   while (@names) {
  721.     $oname = $name = shift @names;
  722.     $firstn = $vonn = $lastn = '';
  723.  
  724.     if ( $revauthor && ($ntype eq A) && ($name =~ /,/) ) {
  725.       $jrn = "";
  726.       if ($name =~ s/[,\s]+([sj]r\.?|I+)\s*$//i) {
  727.         $jrn = ", " . $1;
  728.       }
  729.       $name =~ s/^(.*)\s*,\s*(.*)/$2 $1$jrn/g;
  730.     }
  731.     $jrn = "";
  732.  
  733.     $name =~ s/[\s~]+([sj]r\.?|\(?edi?t?o?r?s?\.?\)?|I+)(,|$)/, $1/i;
  734.     $name =~ s/,,/,/g;
  735.     ($nname, $jrn) = split(/,[^~]/, $name, 2);
  736. #    print "name: $name  -> $nname : $jrn\n";
  737.     $nname =~ s/\s+$//;
  738.     $jrn =~ s/^[\s~]+//;
  739.     $jrn =~ s/,$//;
  740.     if ($jrn =~ /\s/) {
  741.       ($jrn, $rest) = $jrn =~ /([sj]r\.?|\(?edi?t?o?r?s?\.?\)?|I+)?,?\s*(.*)$/i;
  742.       unshift(@names, $rest);
  743.     }
  744.     $jrn =~ s/([^\\])~/$1 /g;
  745.     ($firstn) = $nname =~ /^((\S* )*)/;
  746.     $nname = substr($nname, length($firstn));
  747.     $lastn = $nname;
  748.     $lastn =~ s/([^\\])~/$1 /g;
  749.     $firstn =~ s/([^\\])~/$1 /g;
  750.     while ($firstn =~ / ([a-z]+ )$/) {
  751.       $rest = $1;
  752.       $vonn = $rest . $vonn;
  753.       $firstn = substr($firstn, 0, length($firstn) - length($rest));
  754.     }
  755.     while ($lastn =~ /^([a-z]+ )/) {
  756.       $rest = $1;
  757.       $vonn .= $rest;
  758.       $lastn = substr($lastn, length($rest));
  759.     }
  760.  
  761.     if ($jrn) {
  762.       if ($jrn =~ /^(et\.?\s*al\.?)|(others)$/i) {
  763.         undef $jrn;
  764.         unshift(@names, "others");
  765.       }
  766.       if ($jrn =~ /^[(]?edi?t?o?r?s?[\.]?[)]?$/i) {
  767.         undef $jrn;
  768.         $editors = 1;
  769.       }
  770.       if ($jrn =~ /^inc[\.]?$/i) {
  771.         $lastn .= ", " . $jrn;
  772.         undef $jrn;
  773.         $corpauthors = 1;
  774.       }
  775.     }
  776.     if ($lastn =~ /^(et\s*al)|(others)$/i) {
  777.       $lastn = "others";
  778.     }
  779.     if ($lastn =~ /\s/) {
  780.       $lastn = "{" . $lastn . "}";
  781.     }
  782.  
  783.     if (!$keyn) {
  784.       if ($corpauthors) {
  785.         ($keyn) = $lastn =~ /^(\S+)/;
  786.       } else {
  787.         ($keyn) = $lastn;       # =~ /(\S+)$/;  # if you want last of Last
  788.       }
  789.       $keyn =~ tr/A-Za-z0-9\/\-//cd;
  790.     }
  791.  
  792.     if ($jrn) {
  793.       $fname .= " and " . $vonn . $lastn . ", " . $jrn . ", " . $firstn;
  794.     } else {
  795.       $fname .= " and " . $firstn . $vonn . $lastn;
  796.     }
  797.   }
  798.   $fname =~ s/^ and\s+//;
  799.   $fname =~ s/\s+$//;
  800.   $fname =~ s/\s+/ /g;
  801.   if ($ntype eq A) {
  802.     if ($corpauthors) {
  803.       &anerror("Corporate Author (%Q) in %A.");
  804.     } elsif ($editors) {
  805.       &anerror("Editors (%E) in %A.");
  806.     }
  807.   } elsif ($ntype eq Q) {
  808.     if ($editors) {
  809.       &anerror("Editors (%E) in %Q.");
  810.     }
  811.   } elsif ($ntype eq E) {
  812.     if ($corpauthors && (!$entry{A})) {
  813.       &anerror("Corporate Author (%Q) in %E.");
  814.     }
  815.   }
  816.  
  817.   return $keyn;
  818. }
  819.  
  820.  
  821.  
  822. ##########################################
  823. # syntax does syntax checking
  824. #
  825. sub syntax {
  826.   foreach $field (@_) {
  827.     if ($field eq AE) {
  828.       if ( (!$entry{A}) && (!$entry{E}) ) {
  829.         &anerror("Missing A and E (Author and Editor) fields.");
  830.       }
  831.     } elsif ($field eq BT) {
  832.       if ( (!$entry{B}) && (!$entry{T}) ) {
  833.         &anerror("Missing T (Title) field.");
  834.       }
  835.     } else {
  836.       if (!$entry{$field}) {
  837.         &anerror("Missing $field field.");
  838.       }
  839.     }
  840.   }
  841. }
  842.  
  843.  
  844.  
  845. ##########################################
  846. # stores error information until it gets printed
  847. #
  848. # This allows us to fully process the entry so we can print out
  849. # valid key information without having to go through ugly gyrations.
  850. #
  851. sub anerror {
  852.   local($err) = @_;
  853.  
  854.   push(@errorstring, $err);
  855.   $errors++;
  856. }
  857.  
  858.  
  859.  
  860. ##########################################
  861. # prints out stored error information
  862. #
  863. sub printerrors {
  864.   local($klen, $errst);
  865.  
  866.   if (@errorstring && (!$nowarnings)) {
  867.     $klen = $maxllength;  # a little short, but most labels aren't this long
  868.     foreach $_ (@errorstring) {
  869.       $errst .= sprintf("%-${klen}s (%5d): %s\n", $key, $errline, $_);
  870.     }
  871.     print STDERR $errst;
  872.   }
  873.   undef @errorstring;
  874.   $errline = $linenum+1;
  875. }
  876.  
  877.  
  878.  
  879. ##########################################
  880. # converts *roff characters to TeX characters
  881. #
  882. # If anyone has any corrections or additions, I'd be happy to see them.
  883. #
  884. # Is there a better way to do this?  (i.e. eval)
  885. #
  886. sub dorofftotex {
  887.   local($_) = @_;
  888.   local($fbraces, $nchanges);
  889.  
  890.   study;                        # presumably this will help us.
  891.  
  892.   # tib: refer format, TeX formatting.
  893.   #      This should probably be set up to read a configuration file into
  894.   #      a variable then use eval.  If there is such a beast as a "detibify"
  895.   #      program, then this won't be necessary.
  896.   if ($tibfmt) {
  897.     1 while s#\\egroup(.*)\\bgroup#{\\Reffont $1}#g;
  898.     s/\\Citefont//g;
  899.     s/\\ACitefont//g;
  900.     s/\\Authfont//g;
  901.     s/\\Titlefont//g;
  902.     s/\\Tomefont/\\sl/g;
  903.     s/\\Volfont//g;
  904.     s/\\Flagfont//g;
  905.     s/\\Reffont/\\rm/g;
  906.     s/\\Smallcapsfont/\\sevenrm/g;
  907.     s/\\Flagstyle//g;            # This should be smarter
  908.  
  909.     if (/\|/) {
  910.       s/\|JAN\|/January/g;       # yes, the parsedate routine can handle
  911.       s/\|FEB\|/February/g;      # these most of the time, but sometimes
  912.       s/\|MAR\|/March/g;         # they're put in the middle of non-date
  913.       s/\|APR\|/April/g;         # strings, so we'd better convert them.
  914.       s/\|MAY\|/May/g;
  915.       s/\|JUN\|/June/g;
  916.       s/\|JUL\|/July/g;
  917.       s/\|AUG\|/August/g;
  918.       s/\|SEP\|/September/g;
  919.       s/\|OCT\|/October/g;
  920.       s/\|NOV\|/November/g;
  921.       s/\|DEC\|/December/g;
  922.  
  923.       # My example of tib format is AGbib from INRIA, so this is set up to
  924.       # handle the common cases for that bibliography.
  925.  
  926.       s/\|UNIV\|/University/g;
  927.       s/\|DEPT\|/Department/g;
  928.       s/\|DCS\|/Department of Computer Science/g;
  929.       s/\|PCS\|/Progr. and Computer Science/g;
  930.       s/\|CSD\|/Computer Science Department/g;
  931.       s/\|TR\|/Technical Report/g;
  932.  
  933.       s/\|COMPJ\|/The Computer Journal/g;
  934.       s/\|JACM\|/Journal of the ACM/g;
  935.       s/\|CACM\|/Communications of the ACM/g;
  936.       s/\|SGPLN\|/Sigplan Notices/g;
  937.       s/\|SIAJC1\|/SIAM Journal on Computing/g;
  938.       s/\|ACTAI2\|/Acta Informatica/g;
  939.       s/\|IEETS1\|/IEEE Transactions on Software Engineering/g;
  940.       s/\|INFPL2\|/Information Processing Letters/g;
  941.       if (s/\|LNCS\|/Lecture Notes in Computer Science/g) {
  942.         $entry{I} .= " " . "Springer-Verlag";
  943.         $entry{C} .= " " . "New York--Heidelberg--Berlin"; }
  944.       if (s/\|IFBSV\|/Inf. Fachb./g) {
  945.         $entry{I} .= " " . "Springer-Verlag";
  946.         $entry{C} .= " " . "New York--Heidelberg--Berlin"; }
  947.       s/\|SCICP\|/Science of Computer Programming/g;
  948.       s/\|SP&E\|/Software---Practice and Experience/g;
  949.       s/\|POPL\|/ACM Symp. on Principles of Progr. Languages/g;
  950.       s/\|TOPLAS\|/ACM Trans. Progr. Languages and Systems/g;
  951.  
  952.       if (s/\|Addison\|/Addison Wesley/g) {
  953.         $entry{C} .= " " . "Reading, MA"; }
  954.       if (s/\|PrHall\|/Prentice Hall/g) {
  955.         $entry{C} .= " " . "Englewood Cliffs, NJ"; }
  956.       if (s/\|NHoll\|/North-Holland/g) {
  957.         $entry{C} .= " " . "Amsterdam"; }
  958.       if (s/\|Cambridge\|/Cambridge University Press/g) {
  959.         $entry{C} .= " " . "New York"; }
  960.       if (s/\|Springer\|/Springer-Verlag/g) {
  961.         $entry{C} .= " " . "New York--Heidelberg--Berlin"; }
  962.  
  963.       s/\|TWEINF\|/Onderafdeling der Informatica, Tech. Hogeschool Twente/g;
  964.       s/\|TUMINF\|/Institut f{\"u}r Informatik, Tech. University M{\"u}nchen/g;
  965.       s/\|HELDCS\|/Department of Computer Science, University of Helsinki/g;
  966.       if (s/\|IBMTJW\|/IBM T.J. Watson Research Center/g) {
  967.         $entry{C} .= " " . "Yorktown Heights, NY"; }
  968.       if (s/\|INRIA\|/INRIA/g) {
  969.         $entry{C} .= " " . "Rocquencourt"; }
  970.       if (s/\|IRIAL\|/IRIA-Laboria/g) {
  971.         $entry{C} .= " " . "Rocquencourt"; }
  972.       $entry{C} =~ s/^\s+//;
  973.       $entry{I} =~ s/^\s+//;
  974.     }
  975.     return $_;
  976.   }
  977.  
  978.   s#_#_U#g;   # _ will be the escape character
  979.  
  980.   # don't do troff character conversion if there aren't any backslashes
  981.   # in the string.  Hopefully this will save a little work.
  982.   if (/\\/) {
  983.  
  984.     # to make commands, we need command characters, but we don't want
  985.     # any of the command characters that they use to be passed through
  986.     # or we'll end up with invalid input.  So, _ is the escape character.
  987.  
  988.     # _U is _
  989.     # _B is a backslash
  990.     # _I is a literal backslash
  991.     # _S is a space
  992.     # _C is {\
  993.     # _L is {
  994.     # _R is }
  995.     # _l is <
  996.     # _g is >
  997.     # _T is ~
  998.     # _A is ^
  999.     # _D is $
  1000.     # _M is $\
  1001.     # _V is |
  1002.     # _E is ${}^
  1003.     # _H is \hbox{
  1004.     # _h is \leavevmode
  1005.     # _c is a special continuation character for long lines
  1006.  
  1007.     # I'm not sure I quite get this -- refer strips off one \ for most
  1008.     # characters it seems.  But other times it doesn't.  Argh!  I'll
  1009.     # go ahead and replace \\ with \ to handle this.  It shouldn't ever
  1010.     # come up that this is bad since \e and \(rs are a real backslashes.
  1011.  
  1012.     s#\\\\#\\#g;                             #  \\    -> \
  1013.  
  1014.     # font changes
  1015.     # if one uses \fP, everything is fine -- otherwise we need to get complex
  1016.     $fbraces = 0;
  1017.     $fbraces += s#\\f[1R]#_Crm_S#g;          #  \f1   -> {\rm 
  1018.     $fbraces += s#\\f[2I]#_Cit_S#g;          #  \f2   -> {\it 
  1019.     $fbraces += s#\\f[3B]#_Cbf_S#g;          #  \f3   -> {\bf 
  1020.     $fbraces -= s#\\fP#_R#g;                 #  \fP   -> }
  1021.     while ($fbraces) {                       # too many {'s
  1022.       if ($fbraces < 0) {
  1023.         $nchanges = s#_R##;
  1024.         &anerror("Used \\fP with no previous font.");
  1025.         $fbraces += $nchanges;
  1026.       } else {    # Changed newline matching because 4.019 had problems
  1027. #        $nchanges = s#(_Cit_S)([\s\S]*)_Crm_S#$1$2_R#;
  1028.         $nchanges = s#(_Cit_S)((.|\n)*)_Crm_S#$1$2_R#;
  1029.         if (!$nchanges)
  1030.           { $nchanges = s#(_Cbf_S)([\s\S]*)_Crm_S#$1$2_R#; }
  1031.         if (!$nchanges)
  1032.           { $nchanges = s#(_C\w\w_S)([\s\S]*)_C\w\w_S#$1$2_R#; }
  1033.         if (!$nchanges) {
  1034.           $_ .= "_R";                        # couldn't get it, so stick a } on
  1035.           $fbraces--;
  1036.           &anerror("Problems with font changing.  Suggest using \\fP.");
  1037.         }
  1038.         $fbraces -= ($nchanges * 2);
  1039.       }
  1040.     }
  1041.  
  1042.     # point size changes
  1043.     # first,  U\s-2NIX\s0   ->   {\sc Unix}
  1044.     s/\b([A-Z])\\s-[12]([A-Z]+)\\s0/_Csc_S$1\L$2\E_R/g;
  1045.     # very similar to font changes.  If \s0 is used, everything is fine.
  1046.     $fbraces = 0;
  1047.     $fbraces += s#\\s-1#_Csmall_S#g;          #  \s-1   -> {\small 
  1048.     $fbraces += s#\\s-2#_Cfootnotesize_S#g;   #  \s-2   -> {\footnotesize
  1049.     $fbraces += s#\\s-3#_Cscriptsize_S#g;     #  \s-3   -> {\scriptsize
  1050.     $fbraces += s#\\s-4#_Ctiny_S#g;           #  \s-4   -> {\tiny
  1051.     $fbraces += s#\\s+1#_Clarge_S#g;          #  \s+1   -> {\large 
  1052.     $fbraces += s#\\s+2#_CLarge_S#g;          #  \s+2   -> {\Large
  1053.     $fbraces += s#\\s+3#_CLARGE_S#g;          #  \s+3   -> {\LARGE
  1054.     $fbraces += s#\\s+4#_Chuge_S#g;           #  \s+4   -> {\huge
  1055.     $fbraces -= s#\\s0#_R#g;                  #  \s0    -> }
  1056.     while ($fbraces) {                        # too many {'s
  1057.       if ($fbraces < 0) {
  1058.         $nchanges = s#_R##;
  1059.         &anerror("Used \\s0 with no previous point size change.");
  1060.         $fbraces += $nchanges;
  1061.       } else {
  1062.         $nchanges = s#(_Csmall_S)(.*)_Clarge_S#$1$2_R#;
  1063.         if (!$nchanges)
  1064.           { $nchanges = s#(_Cfootnotesize_S)(.*)_CLarge_S#$1$2_R#; }
  1065.         if (!$nchanges)
  1066.           { $nchanges = s#(_Cscriptsize_S)(.*)_CLARGE_S#$1$2_R#; }
  1067.         if (!$nchanges)
  1068.           { $nchanges = s#(_Clarge_S)(.*)_Csmall_S#$1$2_R#; }
  1069.         if (!$nchanges)
  1070.           { $nchanges = s#(_CLarge_S)(.*)_Cfootnotesize_S#$1$2_R#; }
  1071.         if (!$nchanges)
  1072.           { $nchanges = s#(_CLARGE_S)(.*)_Cscriptsize_S#$1$2_R#; }
  1073.         if (!$nchanges) {
  1074.           $_ .= "_R";                         # last resort.  Add an }.
  1075.           $fbraces--;
  1076.           &anerror("Problems with point size changing.  Suggest using \\s0.");
  1077.         }
  1078.         $fbraces -= ($nchanges * 2);
  1079.       }
  1080.     }
  1081.  
  1082.  
  1083.     # other troff special characters
  1084.     # some of these aren't available as standard TeX, so I made up replacements.
  1085.     # Perhaps they should be def'ed in a preamble and used that way, but I
  1086.     # doubt most files use \(rg, \(ct, and such, so why waste resources.
  1087.     # If you're really concerned about eth, thorn, yogh, or ogonek, go get
  1088.     # the cmoer fonts -- they do the characters right.
  1089.  
  1090.     # grab some common overstrikes made by people who don't have a real
  1091.     # troff manual or implementation.
  1092.  
  1093.     s#\\o'(\w)\\\(aa'#_C'$1_R#g;             # \o'e\(aa'  -> {\'e}
  1094.     s#\\o'(\w)\\\(ga'#_C`$1_R#g;             # \o'e\(ga'  -> {\`e}
  1095.  
  1096.     # Lots of bibliographies from Europe use \:o to mean \(o:, etc.  Both
  1097.     # Elan troff and groff don't know what this means, so I don't do the
  1098.     # conversion by default.  Use '-overstrike' to get this behaviour.
  1099.  
  1100.     if ($overstrike) {
  1101.       s#\\([:`'^~,v/o])([AEIOUYaeiouyNnCcSs])#\\\($2$1#g;
  1102.     }
  1103.  
  1104.     s#\\\(bu#_Mbullet_D#g;                   # \(bu  -> $\bullet$
  1105.     s#\\\(ci#_Mbigcirc_D#g;                  # \(ci  -> $\bigcirc$
  1106.     s#\\\(sq#_MBox_D#g;                      # \(sq  -> $\Box$
  1107.     s#\\\(ct#_h_Brm_Brlap/c_R#g;             # \(ct  -> \hbox{\rm\rlap/c}
  1108.     s#\\\(rg#_h_Braise.6em_H_Booalign_L_L_Bmathhexbox20D_R_Bcrcr\n_Bhfil_Braise.07ex_Hr_R_Bhfil_R_R_R#g;
  1109.     s#\\\(co#_h_Braise.6em_H_Bcopyright_R_R#g;
  1110.     s#\\\(lh#_MLongleftarrow_D#g;            # \(lh  -> $\Longleftarrow$ #wrong!
  1111.     s#\\\(rh#_MLongrightarrow_D#g;           # \(rh  -> $\Longrightarrow$
  1112.     s#\\\(dg#_Bdag #g;                       # \(dg  -> \dag
  1113.     s#\\\(dd#_Bddag #g;                      # \(dd  -> \ddag
  1114.     s#\\\(sc#_BS #g;                         # \(sc  -> \S
  1115.     s#\\\(br#_D_V_D#g;                       # \(br  -> $|$
  1116.     s#\\\(fm#_E_Bprime_D#g;                  # \(fm  -> ${}^\prime$
  1117.     s#\\\(de#_E_Bcirc_D#g;                   # \(de  -> ${}^\circ$
  1118.     s#\\\(em#--#g;                           # \(em  -> --
  1119.     s#\\\(hy#-#g;                            # \(hy  -> -
  1120.     s#\\\(ru#_Cvrule width1.2ex height0.1ex depth0ex_R#g;
  1121.     s#\\\(ul#_Cvrule width1.2ex height-.3ex depth.4ex_R#g;
  1122.     s#\\\-#---#g;                            # \-    -> --
  1123.     s#\\\(aa#_C'_L _R_R#g;                   # \(aa  -> {\'{ }}
  1124.     s#\\'#_C'_L _R_R#g;                      # \'    -> {\'{ }}
  1125.     s#\\\(ga#_C`_L _R_R#g;                   # \(ga  -> {\`{ }}
  1126.     s#\\`#_C`_L _R_R#g;                      # \`    -> {\`{ }}
  1127.     s#\\\(sl#/#g;                            # \(sl  -> /
  1128.     s#\\e#_I#g;                              # \e    -> $\backslash$
  1129.     s#\\0#_T#g;                              # \0    -> ~
  1130.     s#\\ #_B #g;                             # '\ '  -> '\ '
  1131.     s#\\\^#_D_B,_D#g;                        # \^    -> $\,$
  1132.     s#\\\|#_D_B:_D#g;                        # \|    -> $\:$
  1133.     s#\\\(fi#fi#g;                           # \(fi  -> fi
  1134.     s#\\\(fl#fl#g;                           # \(fl  -> fl
  1135.     s#\\\(ff#ff#g;                           # \(ff  -> ff
  1136.     s#\\\(Fi#ffi#g;                          # \(Fi  -> ffi
  1137.     s#\\\(Fl#ffl#g;                          # \(Fl  -> ffl
  1138.  
  1139.     s#\\\(pl#_D+_D#g;                        # \(pl  -> $+$
  1140.     s#\\\(mi#_D-_D#g;                        # \(mi  -> $-$
  1141.     s#\\\(mu#_Mtimes_D#g;                    # \(mu  -> $\times$
  1142.     s#\\\(di#_Mdiv_D#g;                      # \(di  -> $\div$
  1143.     s#\\\(\+\-#_Mpm_D#g;                     # \(+-  -> $\pm$
  1144.     s#\\\(no#_Mneg_D#g;                      # \(no  -> $\neg$
  1145.     s#\\\(\*\*#_Mast_D#g;                    # \(**  -> $\ast$
  1146.     s#\\\(eq#_D=_D#g;                        # \(eq  -> $=$
  1147.     s#\\\(>=#_Mgeq_D#g;                      # \(>=  -> $\geq$
  1148.     s#\\\(<=#_Mleq_D#g;                      # \(<=  -> $\leq$
  1149.     s#\\\(==#_Mequiv_D#g;                    # \(==  -> $\equiv$
  1150.     s#\\\(~=#_Msimeq_D#g;                    # \(~=  -> $\simeq$
  1151.     s#\\\(ap#_Msim_D#g;                      # \(ap  -> $\sim$
  1152.     s#\\\(!e#_Mneq_D#g;                      # \(!e  -> $\neq$
  1153.     s#\\\(\->#_Mrightarrow_D#g;              # \(->  -> $\rightarrow$
  1154.     s#\\\(<\-#_Mleftarrow_D#g;               # \(<-  -> $\leftarrow$
  1155.     s#\\\(ua#_Muparrow_D#g;                  # \(ua  -> $\uparrow$
  1156.     s#\\\(da#_Mdownarrow_D#g;                # \(da  -> $\downarrow$
  1157.     s#\\\(cu#_Mcup_D#g;                      # \(cu  -> $\cup$
  1158.     s#\\\(ca#_Mcap_D#g;                      # \(ca  -> $\cap$
  1159.     s#\\\(sb#_Msubset_D#g;                   # \(sb  -> $\subset$
  1160.     s#\\\(sp#_Msupset_D#g;                   # \(sp  -> $\supset$
  1161.     s#\\\(ib#_Msubseteq_D#g;                 # \(ib  -> $\subseteq$
  1162.     s#\\\(ip#_Msupseteq_D#g;                 # \(ip  -> $\supseteq$
  1163.     s#\\\(if#_Minfty_D#g;                    # \(if  -> $\infty$
  1164.     s#\\\(es#_Memptyset_D#g;                 # \(es  -> $\emptyset$
  1165.     s#\\\(is#_Mint_D#g;                      # \(is  -> $\int$
  1166.     s#\\\(pd#_Mpartial_D#g;                  # \(pd  -> $\partial$
  1167.     s#\\\(sr#_Msurd_D#g;                     # \(sr  -> $\surd$
  1168.     s#\\\(gr#_Mnabla_D#g;                    # \(gr  -> $\nabla$
  1169.     s#\\\(pt#_Mpropto_D#g;                   # \(pt  -> $\propto$
  1170.     s#\\\(mo#_Min_D#g;                       # \(mo  -> $\in$
  1171.     s#\\\(or#_Mmid_D#g;                      # \(or  -> $\mid$
  1172.     s#\\\((\d)(\d)#_D$1_Bover$2_D#g;         # \(14  -> $1\over4$
  1173.  
  1174.     s#\\\(m\.#_Mcdot_D#g;                    # \(m.  -> $\cdot$
  1175.     s#\\\(!s#_Mnot_Bsubset_D#g;              # \(!s  -> $\not\subset$
  1176.     s#\\\(an#_Mwedge_D#g;                    # \(an  -> $\wedge$
  1177.     s#\\\(lo#_Mvee_D#g;                      # \(lo  -> $\vee$
  1178.     s#\\\(tf#_D_H._R_Braise.9ex_H._R_H._R_D#g;# \(tf -> .:.
  1179.     s#\\\(cm#_Mni_D#g;                       # \(cm  -> $\ni$
  1180.     s#\\\(fa#_Mforall_D#g;                   # \(fa  -> $\forall$
  1181.     s#\\\(te#_Mexists_D#g;                   # \(te  -> $\exists$
  1182.     s#\\\(!m#_Mnotin_D#g;                    # \(!m  -> $\notin$
  1183.     s#\\\(a\+#_Moplus_D#g;                   # \(a+  -> $\oplus$
  1184.     s#\\\(ax#_Motimes_D#g;                   # \(ax  -> $\otimes$
  1185.     s#\\\(ag#_Mangle_D#g;                    # \(ag  -> $\angle$
  1186.     s#\\\(rn#_Moverline_L _R_D#g;            # \(rn  -> $\overline{ }$
  1187.     s#\\\(<<#_Mll_D#g;                       # \(<<  -> $\ll$
  1188.     s#\\\(>>#_Mgg_D#g;                       # \(>>  -> $\gg$
  1189.     s#\\\(<>#_Mleftrightarrow_D#g;           # \(<>  -> $\leftrightarrow$
  1190.     s#\\\(//#_D/_D#g;                        # \(//  -> $/$
  1191.     s#\\\(L<#_Mlangle_D#g;                   # \(L<  -> $\langle$
  1192.     s#\\\(R>#_Mrangle_D#g;                   # \(R>  -> $\rangle$
  1193.     s#\\\(dm#_Mdiamond_D#g;                  # \(dm  -> $\diamond$
  1194.     s#\\\(lt#_Mlbrace_D#g;                   # \(lt  -> $\lbrace$
  1195.     s#\\\(rt#_Mrbrace_D#g;                   # \(rt  -> $\rbrace$
  1196.     s#\\\(lb#_Mlfloor_D#g;                   # \(lb  -> $\lfloor$
  1197.     s#\\\(rt#_Mrfloor_D#g;                   # \(rt  -> $\rfloor$
  1198.     s#\\\(lk#_Mlbrace_D#g;                   # \(lk  -> $\lbrace$
  1199.     s#\\\(rk#_Mrbrace_D#g;                   # \(rk  -> $\rbrace$
  1200.     s#\\\(lf#_Mlfloor_D#g;                   # \(lf  -> $\lfloor$
  1201.     s#\\\(rf#_Mrfloor_D#g;                   # \(rf  -> $\rfloor$
  1202.     s#\\\(lc#_Mlceil_D#g;                    # \(lc  -> $\lceil$
  1203.     s#\\\(rc#_Mrceil_D#g;                    # \(rc  -> $\rceil$
  1204.  
  1205.     s#\\\(bv#_Cmbox_Cboldmath_Mmid_D_R_R#g;  # \(bv  -> {\mbox{\boldmath$\mid$}}
  1206.     s#\\\(bx#_Cvrule width.5em height.6em depth-.1em_R#g;
  1207.     s#\\\(cf#^#g;                            # \(cf  -> ^
  1208.     s#\\\(al#_Maleph_D#g;                    # \(al  -> $\aleph$
  1209.     s#\\\(If#_MIm_D#g;                       # \(If  -> $\Im$
  1210.     s#\\\(Rf#_MRe_D#g;                       # \(Rf  -> $\Re$
  1211.     s#\\\(ws#_Mwp_D#g;                       # \(ws  -> $\wp$
  1212.     s#\\\(mt#_E_Bprime_D#g;                  # \(mt  -> ${}^\prime$
  1213.     s#\\\(sd#_E_L_Bprime_B!_Bprime_R_D#g;    # \(sd  -> ${}^{\prime\!\prime}$
  1214.     s#\\\(pa#_BP#g;                          # \(pa  -> \P
  1215.     s#\\\(Cc#_Mclubsuit_D#g;                 # \(Cc  -> $\clubsuit$
  1216.     s#\\\(Cd#_Mdiamondsuit_D#g;              # \(Cd  -> $\diamondsuit$
  1217.     s#\\\(Ch#_Mheartsuit_D#g;                # \(Ch  -> $\heartsuit$
  1218.     s#\\\(Cs#_Mspadesuit_D#g;                # \(Cs  -> $\spadesuit$
  1219.     s#\\\(bt#_Mperp_D#g;                     # \(bt  -> $\perp$
  1220.     s#\\\(<:#_MLeftarrow_D#g;                # \(<:  -> $\Leftarrow$
  1221.     s#\\\(:>#_MRightarrow_D#g;               # \(:>  -> $\Rightarrow$
  1222.     s#\\\(io#_MLeftrightarrow_D#g;           # \(io  -> $\Leftrightarrow$
  1223.     s#\\\(u=#_MUparrow_D#g;                  # \(u=  -> $\Uparrow$
  1224.     s#\\\(d=#_MDownarrow_D#g;                # \(d=  -> $\Downarrow$
  1225.     s#\\\(r1#_Mrightleftharpoons_D#g;        # \(r1  -> $\rightleftharpoons$
  1226.     s#\\\(r2#_Mleftharpoondown_D#g;          # \(r2  -> $\leftharpoondown$
  1227.     s#\\\(cr#_Mhookleftarrow_D#g;            # \(cr  -> $\hookleftarrow$
  1228.     s#\\\(AL#_M_D#g;                # \(AL  ->
  1229.     s#\\\(DL#_M_D#g;                # \(DL  ->
  1230.  
  1231.     s#\\\(\*a#_Malpha_D#g;                   # \(*a  -> $\alpha$
  1232.     s#\\\(\*b#_Mbeta_D#g;                    # \(*b  -> $\beta$
  1233.     s#\\\(\*c#_Mxi_D#g;                      # \(*c  -> $\xi$
  1234.     s#\\\(\*d#_Mdelta_D#g;                   # \(*d  -> $\delta$
  1235.     s#\\\(\*e#_Mvarepsilon_D#g;              # \(*e  -> $\varepsilon$
  1236.     s#\\\(\*f#_Mphi_D#g;                     # \(*f  -> $\phi$
  1237.     s#\\\(\*g#_Mgamma_D#g;                   # \(*g  -> $\gamma$
  1238.     s#\\\(\*h#_Mtheta_D#g;                   # \(*h  -> $\theta$
  1239.     s#\\\(\*i#_Miota_D#g;                    # \(*i  -> $\iota$
  1240.     s#\\\(\*k#_Mkappa_D#g;                   # \(*k  -> $\kappa$
  1241.     s#\\\(\*l#_Mlambda_D#g;                  # \(*l  -> $\lambda$
  1242.     s#\\\(\*m#_Mmu_D#g;                      # \(*m  -> $\mu$
  1243.     s#\\\(\*n#_Mnu_D#g;                      # \(*n  -> $\nu$
  1244.     s#\\\(\*o#_Do_D#g;                       # \(*o  -> $o$
  1245.     s#\\\(\*p#_Mpi_D#g;                      # \(*p  -> $\pi$
  1246.     s#\\\(\*q#_Mpsi_D#g;                     # \(*q  -> $\psi$
  1247.     s#\\\(\*r#_Mrho_D#g;                     # \(*r  -> $\rho$
  1248.     s#\\\(\*s#_Msigma_D#g;                   # \(*s  -> $\sigma$
  1249.     s#\\\(\*t#_Mtau_D#g;                     # \(*t  -> $\tau$
  1250.     s#\\\(\*u#_Mupsilon_D#g;                 # \(*u  -> $\upsilon$
  1251.     s#\\\(\*w#_Momega_D#g;                   # \(*w  -> $\omega$
  1252.     s#\\\(\*x#_Mchi_D#g;                     # \(*x  -> $\chi$
  1253.     s#\\\(\*y#_Meta_D#g;                     # \(*y  -> $\eta$
  1254.     s#\\\(\*z#_Mzeta_D#g;                    # \(*z  -> $\zeta$
  1255.     s#\\\(ts#_Mvarsigma_D#g;                 # \(ts  -> $\varsigma$
  1256.     s#\\\(\*C#_MXi_D#g;                      # \(*C  -> $\Xi$
  1257.     s#\\\(\*D#_MDelta_D#g;                   # \(*D  -> $\Delta$
  1258.     s#\\\(\*F#_MPhi_D#g;                     # \(*F  -> $\Phi$
  1259.     s#\\\(\*G#_MGamma_D#g;                   # \(*G  -> $\Gamma$
  1260.     s#\\\(\*H#_MTheta_D#g;                   # \(*H  -> $\Theta$
  1261.     s#\\\(\*L#_MLambda_D#g;                  # \(*L  -> $\Lambda$
  1262.     s#\\\(\*P#_MPi_D#g;                      # \(*P  -> $\Pi$
  1263.     s#\\\(\*Q#_MPsi_D#g;                     # \(*Q  -> $\Psi$
  1264.     s#\\\(\*R#_Crm_SP_R#g;                   # \(*R  -> {\rm P}
  1265.     s#\\\(\*S#_MSigma_D#g;                   # \(*S  -> $\Sigma$
  1266.     s#\\\(\*U#_Crm_SY_R#g;                   # \(*U  -> {\rm Y}
  1267.     s#\\\(\*W#_MOmega_D#g;                   # \(*W  -> $\Omega$
  1268.     s#\\\(\*Y#_Crm_SH_R#g;                   # \(*Y  -> {\rm H}
  1269.     s#\\\(\*(\w)#_Crm_S$1_R#g;               # \(*_  -> {\rm _}
  1270.  
  1271.     # from the -mm macros
  1272.  
  1273.     s#\\\*\(Tm#_E_Crm_Buppercase_LTM_R_R_D#g;# \*(Tm -> ${}^{\rm\uppercase{TM}}$
  1274.  
  1275.     # I am SO disgusted with troff.  It seems that unless the -ms option is
  1276.     # given, all accents are done in the -mm way e\*'.  In fact, when the
  1277.     # -ms option is given, only the original 7 accents are done postfix.
  1278.  
  1279.     s#(ij)\\\*(['`])#_C$1_B$2_R#g;           # i\*'  -> {\'\i}
  1280.     s#(ij)\\\*:#_C"_B$1_R#g;                 # i\*:  -> {\"\i}
  1281.     s#(ij)\\\*\^#_C_A_B$1_R#g;               # i\*^  -> {\^\i}
  1282.     s#(\w)\\\*(['`])#_C$2$1_R#g;             # e\*'  -> {\'e}
  1283.     s#(\w)\\\*\^#_C_A$1_R#g;                 # e\*^  -> {\^e}
  1284.     s#(\w)\\\*~#_C_T$1_R#g;                  # e\*~  -> {\~e}
  1285.     s#(\w)\\\*:#_C"$1_R#g;                   # e\*:  -> {\"e}
  1286.     s#(\w)\\\*;#_C"$1_R#g;                   # U\*;  -> {\"U}
  1287.     s#(\w)\\\*,#_Cc_L$1_R_R#g;               # e\*,  -> {\c{e}}
  1288.  
  1289.     # from the Berkeley -ms macros
  1290.  
  1291.     s#\\\*\-#--#g;                           # \*-   -> --
  1292.     s#\\\*Q#``#g;                            # \*Q   -> ``
  1293.     s#\\\*U#''#g;                            # \*U   -> ''
  1294.     s#\\\*\(BU#_Mbullet_D#g;                 # \*(BU -> $\bullet$
  1295.     s#\\\*\(EM#--#g;                         # \*(EM -> --
  1296.  
  1297.     # changed in 0.8.1, from e\*' to \*'e.
  1298.     # These only get used if the above fail (which they don't).
  1299.     #  An '-ms' option?  What a hack..
  1300.  
  1301.     s#\\\*(['`])(ij)#_C$2_B$1_R#g;           # \*'i  -> {\'\i}
  1302.     s#\\\*:(ij)#_C"_B$1_R#g;                 # \*:i  -> {\"\i}
  1303.     s#\\\*\^(ij)#_C_A_B$1_R#g;               # \*^i  -> {\^\i}
  1304.     s#\\\*(['`])(\w)#_C$1$2_R#g;             # \*'e  -> {\'e}
  1305.     s#\\\*\^(\w)#_C_A$1_R#g;                 # \*^e  -> {\^e}
  1306.     s#\\\*~(\w)#_C_T$1_R#g;                  # \*~e  -> {\~e}
  1307.     s#\\\*C(\w)#_Cv_L$1_R_R#g;               # \*Cc  -> {\v{c}}
  1308.     s#\\\*,(\w)#_Cc_L$1_R_R#g;               # \*,e  -> {\c{e}}
  1309.     s#\\\*:(\w)#_C"$1_R#g;                   # \*:e  -> {\"e}
  1310.  
  1311.     s#(\w)\\\*v#_Cv_L$1_R_R#g;               # c\*v  -> {\v{c}}
  1312.     s#(\w)\\\*_U#_C=$1_R#g;                  # e\*_  -> {\=e}
  1313.     s#([Oo])\\\*/#_C$1_R#g;                  # o\*/  -> {\o}
  1314.     s#(\w)\\\*\.#_Cd_L$1_R_R#g;              # e\*.  -> {\d{e}}
  1315.     s#([Aa])\\\*o#_C$1$1_R#g;                # a\*o  -> {\aa}
  1316.  
  1317.     s#\\\*([!?])#$1`#g;                      # \*?   -> ?`
  1318.     s#\\\*8#_Css_R#g;                        # \*8   -> {\ss}
  1319.     s#\\\*3#_h_Blower.5ex_H3_R_R#g;          # \*3   -> \hbox{\lower.5ex 3}
  1320.     s#\\\*\(Th#_hI_Bhskip-.6ex_Braise.5ex_H_Mscriptscriptstyle_Bsupset_D_R_R#g;
  1321.     s#\\\*\(th#_h_Clower.3ex_H_Blarge l_R_R_Bhskip-.52ex o_R#g;
  1322.     s#\\\*D\-#_h_Booalign_L_LD_R_Bcrcr\n_Bhskip.2ex_Braise.25ex_H-_R_Bhfil_R_R#g;
  1323.     s#\\\*d\-#_h_Booalign_L_Mpartial_D_Bcrcr\n_Bhskip.55ex_Braise.7ex_H-_R_Bhfil_R_R#g;
  1324.     s#\\\*\(([AO])e#_C$1E_R#g;               # \*(Ae -> {\AE}
  1325.     s#\\\*\(([ao])e#_C$1e_R#g;               # \*(ae -> {\ae}
  1326.     s#\\\*q#_Cc_Lo_R_R#g;                    # \*q   -> {\c{o}}
  1327.  
  1328.     # International (Roman-8) symbols
  1329.  
  1330.     s#\\\(\.\.#_C"_B _R#g;                   # \(..  -> {\"\ }
  1331.     s#\\\(([AEIOUYaeouy]):#_C"$1_R#g;        # \(A:  -> {\"A}
  1332.     s#\\\(([AEIOUaceouy])'#_C'$1_R#g;        # \(A'  -> {\'A}
  1333.     s#\\\(([AEIOUaeouy])`#_C`$1_R#g;         # \(A`  -> {\`A}
  1334.     s#\\\(([AEIOUaeouy])\^#_C_A$1_R#g;       # \(A^  -> {\^A}
  1335.     s#\\\(i:#_C"_Bi_R#g;                     # \(i:  -> {\"\i}
  1336.     s#\\\(i(['`])#_C$1_Bi_R#g;               # \(i'  -> {\'\i}
  1337.     s#\\\(i\^#_C_A_Bi_R#g;                   # \(i^  -> {\^\i}
  1338.     s#\\\(([ANOano])~#_C_T$1_R#g;            # \(A~  -> {\~A}
  1339.     s#\\\(([CcOo]),#_Cc_L$1_R_R#g;           # \(c,  -> {\c{c}}
  1340.     s#\\\(([Ss])v#_Cv_L$1_R_R#g;             # \(sv  -> {\v{s}}
  1341.     s#\\\(([Oo])/#_C$1_R#g;                  # \(O/  -> {\O}
  1342.     s#\\\(ss#_Css_R#g;                       # \(ss  -> {\ss}
  1343.     s#\\\(L\-#_Cpounds_R#g;                  # \(L-  -> {\pounds}
  1344.     s#\\\(L=#_Cpounds_R#g;                   # \(L=  -> {\pounds}   # (Wrong!)
  1345.     s#\\\(Y=#_h_Brm_Brlap=Y_R#g;             # \(Y=  -> \hbox{\rm\rlap=Y}
  1346.     s#\\\(I([!?])#$1`#g;                     # \I!   -> !`
  1347.     s#\\\((AE|ae|OE|oe)#_C$1_R#g;            # \(AE  -> {\AE}
  1348.     s#\\\(([Aa])o#_C$1$1_R#g;                # \(Ao  -> {\AA}
  1349.     s#\\\(TH#_hI_Bhskip-.6ex_Braise.5ex_H_Mscriptscriptstyle_Bsupset_D_R_R#g;
  1350.     s#\\\(th#_h_Clower.3ex_H_Blarge l_R_R_Bhskip-.52ex o_R#g;
  1351.     s#\\\(D\-#_h_Booalign_L_LD_R_Bcrcr\n_Bhskip.2ex_Braise.25ex_H-_R_Bhfil_R_R#g;
  1352.     s#\\\(d\-#_h_Booalign_L_Mpartial_D_Bcrcr\n_Bhskip.55ex_Braise.7ex_H-_R_Bhfil_R_R#g;
  1353.     s#\\\(([ao])_U#_E_Cb_Cscriptsize $1_R_R_D#g;
  1354.  
  1355.     # The "Scandinavian currency sign" is made with a bold \circ rlap'ed 
  1356.     # with 8 .'s.  Big, long, and ugly, but the result is not too bad.
  1357.  
  1358.     s#\\\(ox#_h_Booalign_Cmbox_Cboldmath_Mcirc_D_R_Bcrcr\n_Bhskip-.04ex_Braise.78ex_H._R_Bhfil_Bcrcr\n_Bhskip-.04ex_Braise.08ex_H._R_Bhfil_Bcrcr\n_c#g;
  1359.     s#_c#_Bhskip.7ex_Braise.78ex_H._R_Bhfil_Bcrcr\n_Bhskip.7ex_Braise.08ex_H._R_Bhfil_Bcrcr\n_c#g;
  1360.     s#_c#_Bhskip-.14ex_Braise.89ex_H._R_Bhfil_Bcrcr\n_Bhskip-.14ex_Braise-.02ex_H._R_Bhfil_Bcrcr\n_c#g;
  1361.     s#_c#_Bhskip.8ex_Braise.89ex_H._R_Bhfil_Bcrcr\n_Bhskip.8ex_Braise-.02ex_H._R_Bhfil_Bcrcr\n_R_R#g;
  1362.  
  1363.     # All the symbols from groff chars.tr that aren't listed above.
  1364.     #   What the heck is this??  not only is a\*: an a umlaut, but so is
  1365.     #   \(a: and also \(:a !  God, I wish troff would get it together!
  1366.     #   Oh, some people ignore all this and use \o to overlap it themselves!
  1367.     #   \(ao is Ao in Roman-8, and an  o in groff.
  1368.     #   \(Cs is Cards Spades in Roman-8 and Currency Scandanavian in groff.
  1369.     #   How do I know which they meant??
  1370.  
  1371.     s#\\\(bs##g;                             # \(bs  -> (not implemented)
  1372.     s#\\\(%0#_h%_Bhskip-.16ex_Blower.15ex_H_Bscriptsize 0_R_R#g;
  1373.     s#\\\(f/#/#g;                            # \(f/  -> /
  1374.     s#\\\(ha#_h_Braise.3em_H_Mscriptstyle_Bwedge_D_R_R#g;
  1375.     s#\\\(ti#_Msim_D#g;                      # \(ti  -> $\sim$
  1376.     s#\\\(\-D#_h_Booalign_L_LD_R_Bcrcr\n_Bhskip.2ex_Braise.25ex_H-_R_Bhfil_R_R#g;
  1377.     s#\\\(Sd#_h_Booalign_L_Mpartial_D_Bcrcr\n_Bhskip.8ex_Braise.7ex_H-_R_Bhfil_R_R#g;
  1378.     s#\\\(TP#_hI_Bhskip-.6ex_Braise.5ex_H_Mscriptscriptstyle_Bsupset_D_R_R#g;
  1379.     s#\\\(Tp#_h_Clower.3ex_H_Blarge l_R_R_Bhskip-.52ex o_R#g;
  1380.     s#\\\(IJ#_LI_Bhskip-.2ex J_R#g;          # \(IJ  -> {I\hskip-.2ex J}
  1381.     s#\\\(ij#_Li_Bhskip-.2ex j_R#g;          # \(ij  -> {i\hskip-.2ex j}
  1382.     s#\\\('([ACEIOUaceou])#_C'$1_R#g;        # \('A  -> {\'A}
  1383.     s#\\\(:([AEIOUYaeouy])#_C"$1_R#g;        # \(:A  -> {\"A}
  1384.     s#\\\(\^([AEIOUaeou])#_C_A$1_R#g;        # \(^A  -> {\^A}
  1385.     s#\\\(`([AEIOUaeou])#_C`$1_R#g;          # \(`A  -> {\`A}
  1386.     s#\\\((['`])i#_C$1_Bi_R#g;               # \('i  -> {\'\i}
  1387.     s#\\\(\^i#_C_A_Bi_R#g;                   # \(^i  -> {\^\i}
  1388.     s#\\\(:i#_C"_Bi_R#g;                     # \(:i  -> {\"\i}
  1389.     s#\\\(~([ANOano])#_C_T$1_R#g;            # \(~A  -> {\~A}
  1390.     s#\\\(v([CcSsZz])#_Cv_L$1_R_R#g;         # \(vs  -> {\v{s}}
  1391.     s#\\\(,([Cc])#_Cc_L$1_R_R#g;             # \(,c  -> {\c{c}}
  1392.     s#\\\(/([OoLl])#_C$1_R#g;                # \(/O  -> {\O}
  1393.     s#\\\(o([Aa])#_C$1$1_R#g;                # \(oA  -> {\AA}
  1394.     s#\\\(a"#_CH_L _R_R#g;                   # \(a"  -> {\H{ }}
  1395.     s#\\\(a\-#_C=_L _R_R#g;                  # \(a-  -> {\={ }}
  1396.     s#\\\(a\.#_C._L _R_R#g;                  # \(a.  -> {\.{ }}
  1397.     s#\\\(a\^#_C_A_L _R_R#g;                 # \(a^  -> {\^{ }}
  1398.     s#\\\(ab#_Cu_L _R_R#g;                   # \(ab  -> {\u{ }}
  1399.     s#\\\(ac#_Cc_L _R_R#g;                   # \(ac  -> {\c{ }}
  1400.     s#\\\(ad#_C"_L _R_R#g;                   # \(ad  -> {\"{ }}
  1401.     s#\\\(ah#_Cv_L _R_R#g;                   # \(ah  -> {\v{ }}
  1402.     s#\\\(a~#_C_T_L _R_R#g;                  # \(a~  -> {\~{ }}
  1403.     s#\\\(ho#_Cc_L _R_R#g;                   # \(ho  -> {\c{ }}  # (wrong!)
  1404.     s#\\\(\.([ij])#_C$1_R#g;                 # \(.i  -> {\i}
  1405.     s#\\\(Do#$#g;                            # \(Do  -> $
  1406.     s#\\\(Po#_Cpounds_R#g;                   # \(Po  -> {\pounds}
  1407.     s#\\\(Ye#_h_Brm_Brlap=Y_R#g;             # \(Ye  -> \hbox{\rm\rlap=Y}
  1408.     s#\\\(Fo#_Mscriptscriptstyle_Bll_D#g;    # \(Fo  -> $\scriptscriptstyle\ll$
  1409.     s#\\\(Fc#_Mscriptscriptstyle_Bgg_D#g;    # \(Fc  -> $\scriptscriptstyle\gg$
  1410.     s#\\\(fo#_Mscriptscriptstyle_l_D#g;      # \(fo  -> $\scriptscriptstyle<$
  1411.     s#\\\(fc#_Mscriptscriptstyle_g_D#g;      # \(fc  -> $\scriptscriptstyle>$
  1412.     s#\\\(r([!?])#$1`#g;                     # \(r!  -> !`
  1413.     s#\\\(OK#_Cmbox_Cboldmath_Msurd_D_R_R#g; # \(OK  ->{\mbox{\boldmath$\surd$}}
  1414.     s#\\\(Of#_E_Cb_Cscriptsize a_R_R_D#g;    # \(Of  -> ${}^{\scriptsize a}}$
  1415.     s#\\\(Om#_E_Cb_Cscriptsize o_R_R_D#g;    # \(Om  -> ${}^{\scriptsize o}}$
  1416.     s#\\\(S(\d)#_E$1_D#g;                    # \(S1  -> ${}^1$
  1417.     s#\\\(lA#_MLeftarrow_D#g;                # \(lA  -> $\Leftarrow$
  1418.     s#\\\(rA#_MRightarrow_D#g;               # \(rA  -> $\Rightarrow$
  1419.     s#\\\(hA#_MLeftrightarrow_D#g;           # \(hA  -> $\Leftrightarrow$
  1420.     s#\\\(dA#_MDownarrow_D#g;                # \(dA  -> $\Downarrow$
  1421.     s#\\\(uA#_MUparrow_D#g;                  # \(uA  -> $\Uparrow$
  1422.     s#\\\(vA#_MUpdownarrow_D#g;              # \(vA  -> $\Updownarrow$
  1423.     s#\\\(va#_Mupdownarrow_D#g;              # \(va  -> $\updownarrow$
  1424.     s#\\\(ba#_Chskip.4ex_Bvrule width.2ex height1.7ex depth0ex_R#g;
  1425.     s#\\\(bb#_h_Bhskip.4ex_H_Booalign_Cvrule width.2ex height.5ex depth.4ex_Bcrcr\n_Bhfil_Braise.8ex_H_Bvrule width.2ex height.9ex depth0ex_R_Bhfil_R_R_R#g;
  1426.     s#\\\(tm#_E_Crm_Buppercase_LTM_R_R_D#g;  # \(tm  -> ${}^{\rm\uppercase{TM}}$
  1427.     s#\\\(ps#_BP#g;                          # \(ps  -> \P
  1428.     s#\\\(en#-#g;                            # \(en  -> -
  1429.     s#\\\(lB#_L_R[#g;                        # \(lB  -> {}[
  1430.     s#\\\(rB#]#g;                            # \(rB  -> ]
  1431.     s#\\\(lC#{#g;                            # \(lC  -> {
  1432.     s#\\\(rC#}#g;                            # \(rC  -> }
  1433.     s#\\\(la#_Mlangle_D#g;                   # \(la  -> $\langle$
  1434.     s#\\\(ra#_Mrangle_D#g;                   # \(ra  -> $\rangle$
  1435.     s#\\\(lq#``#g;                           # \(lq  -> ``
  1436.     s#\\\(rq#''#g;                           # \(rq  -> ''
  1437.     s#\\\(oq#`#g;                            # \(oq  -> `
  1438.     s#\\\(at#@#g;                            # \(at  -> @
  1439.     s#\\\(sh#\##g;                           # \(sh  -> #
  1440.     s#\\\(rs#_I#g;                           # \(rs  -> $\backslash$
  1441.     s#\\\(3d#_D_H._R_Braise.9ex_H._R_H._R_D#g;# \(3d -> .:.
  1442.     s#\\\(~~#_Mapprox_D#g;                   # \(~~  -> $\approx$
  1443.     s#\\\(!=#_Mneq_D#g;                      # \(!=  -> $\neq$
  1444.     s#\\\(=~#_Mcong_D#g;                     # \(=~  -> $\cong$
  1445.     s#\\\(AN#_Mwedge_D#g;                    # \(AN  -> $\wedge$
  1446.     s#\\\(OR#_Mvee_D#g;                      # \(OR  -> $\vee$
  1447.     s#\\\(Ah#_Maleph_D#g;                    # \(Ah  -> $\aleph$
  1448.     s#\\\(Im#_MIm_D#g;                       # \(Im  -> $\Im$
  1449.     s#\\\(Re#_MRe_D#g;                       # \(Re  -> $\Re$
  1450.     s#\\\(md#_Mcdot_D#g;                     # \(md  -> $\cdot$
  1451.     s#\\\(nm#_Mnotin_D#g;                    # \(nm  -> $\notin$
  1452.     s#\\\(pp#_Mperp_D#g;                     # \(pp  -> $\perp$
  1453.     s#\\\(c\*#_Motimes_D#g;                  # \(c*  -> $\otimes$
  1454.     s#\\\(c\+#_Moplus_D#g;                   # \(c+  -> $\oplus$
  1455.     s#\\\(\-h#_Mhbar_D#g;                    # \(-h  -> $\hbar$
  1456.     s#\\\(CL#_Mclubsuit_D#g;                 # \(CL  -> $\clubsuit$
  1457.     s#\\\(SP#_Mspadesuit_D#g;                # \(SP  -> $\spadesuit$
  1458.     s#\\\(HE#_Mheartsuit_D#g;                # \(HE  -> $\heartsuit$
  1459.     s#\\\(DI#_Mdiamondsuit_D#g;              # \(DI  -> $\diamondsuit$
  1460.     s#\\\(CR#_Mhookleftarrow_D#g;            # \(CR  -> $\hookleftarrow$
  1461.     s#\\\(st#_Mni_D#g;                       # \(st  -> $\ni$
  1462.     s#\\\(/_U#_Mangle_D#g;                   # \(/_  -> $\angle$
  1463.     s#\\\(\-\+#_Mmp_D#g;                     # \(-+  -> $\mp$
  1464.     s#\\\(nc#_Mnot_Bsupset_D#g;              # \(nc  -> $\not\supset$
  1465.     s#\\\(ne#_Mnot_Bequiv_D#g;               # \(ne  -> $\not\equiv$
  1466.  
  1467.  
  1468.     # misc
  1469.  
  1470.     s#\\u([^\\]*)\\d#_Braisebox_L1ex_R_L$1_R#g;
  1471.     s#\\d([^\\]*)\\u#_Braisebox_L-1ex_R_L$1_R#g;
  1472.     s#\\z(.)#_Brlap_L$1_R#g;                 # \z|_   -> L
  1473.     s#\\\*\(mm#mm#g;                         # \*(mm  -> mm
  1474.  
  1475.     s#\\&##g;                                # \&     ->
  1476.  
  1477.   }   # done with troff special chars
  1478.  
  1479.   # finally, do eqn processing if they asked for it.
  1480.   #
  1481.   # This is very crude, and handles only the very simple eqn constructs.
  1482.   # We should have some support for reading in eqn definitions rather
  1483.   # than hard-coding some.
  1484.   #
  1485.   if ($handleeqn) {
  1486.     local ($oldline);
  1487.     # print STDERR "\nfrom: $_\n" if /@.*@/;
  1488.     # replace  @blah $\foo$ bar@   with   @blah \foo bar@
  1489.     1 while s/@([^@]* su[bp] [^@]*)_M([^@]*)_D([^@]*)@/@$1_B$2$3@/g;
  1490.     1 while s/@([^@]*)_M([^@]*)_D([^@]* su[bp] [^@]*)@/@$1_B$2$3@/g;
  1491.     while (/@.*@/) {
  1492.       $oldline = $_;
  1493.       s/@\s*roman\s+([^@]*)@/@$1@/g;
  1494.       s/@\s*{\s*([^\s@]+)\s*sub\s+([^\s@]+)\s*}\s*sup\s+([^\s@]+)\s*([^@]*)@/_L_D_Crm_S$1_R__L$2_R_A_L$3_R_D_R@$4@/g;
  1495.       s/@\s*([^\s@]+)\s*sub\s+([^\s@]+)\s*([^@]*)@/_L_D_Crm_S$1_R__L$2_R_D_R@$3@/g;
  1496.       s/@\s*([^\s@]+)\s*sup\s+([^\s@]+)\s*([^@]*)@/_L_D_Crm_S$1_R_A_L$2_R_D_R@$3@/g;
  1497.       s/_L_D_Crm_S""_R/_L_D_L_R/g;   # handle @ "" sub 18 @
  1498.       s/@mu@/_Mmu_D/g;
  1499.       s/@angstrom@/_CAA_R/g;
  1500.       s/@co2@/@CO sub 2@/g;
  1501.       s/@no2@/@NO sub 2@/g;
  1502.       s/@nox@/@NO sub x@/g;
  1503.       s/@n2@/@N sub 2@/g;
  1504.       s/@so2@/@SO sub 2@/g;
  1505.       s/@so4@/@{SO sub 4} sup 2-@/g;
  1506.       s/@no3@/@{NO sub 3} sup -@/g;
  1507.       s/@hno3@/@HNO sub 3@/g;
  1508.       if ($oldline eq $_) {
  1509.         s/@\s*([^\s@]+)\s*([^@]*)@/_L$1_R@$2@/g;
  1510.       }
  1511.       s/@\s*@//g;
  1512.       # print STDERR "  to: $_\n";
  1513.     }
  1514.   }
  1515.  
  1516.   # protect TeX characters
  1517.   if ($protectTeX) {
  1518.     s/\\/_I/g;
  1519.     s/#/\\#/g;
  1520.     s/\$/\\$/g;
  1521.     s/%/\\%/g;
  1522.     s/&/\\&/g;
  1523.     s/{/_D\\lbrace_D/g;
  1524.     s/}/_D\\rbrace_D/g;
  1525.     s/\|/$|$/g;
  1526.     s/</\$<$/g;
  1527.     s/>/\$>$/g;
  1528.     s/\^/\\^{}/g;
  1529.     s/~/\\~{}/g;
  1530.   }
  1531.  
  1532.   # now convert our escaped characters back to their real selves
  1533.   s/_B/\\/g;
  1534.   s/_I/\$\\backslash$/g;
  1535.   s/_C/{\\/g;
  1536.   s/_S/ /g;
  1537.   s/_L/{/g;
  1538.   s/_R/}/g;
  1539.   s/_l/</g;
  1540.   s/_g/>/g;
  1541.   s/_T/~/g;
  1542.   s/_A/^/g;
  1543.   s/_D/$/g;
  1544.   s/_M/\$\\/g;
  1545.   s/_V/|/g;
  1546.   s/_E/\${}^/g;
  1547.   s/_H/\\hbox{/g;
  1548.   s/_h/\\leavevmode\n\\hbox{/g;
  1549.   s/_U/\\_/g;
  1550.   s/\n\n/\\par\n/g;           # this is for fields that want paragraphs
  1551.   return $_;
  1552. }
  1553.  
  1554. ##########################################
  1555. # This converts IBMish control character combinations into troff
  1556. # This is new and mostly untested.
  1557. # Why troff?  We convert ibm to troff, then troff to TeX.  That
  1558. # way people can use this program to convert refer w/controls into
  1559. # plain refer.  Or they can get the full blown refer->TeX.
  1560. #
  1561. # refer(c) -> refer     r2b -n -der -ibm
  1562. # refer(c) -> TeX       r2b -ibm
  1563. # refer(c) -> tib       r2b -der -ibm
  1564. #
  1565. sub doibmtoroff {
  1566.   local($_) = @_;
  1567.  
  1568.   if (/[\200-\376]/) {
  1569.     # use the -ms i\*' for accents, as all troff's can handle that.
  1570.     # I'd rather use \('i, but that works for groff, while eroff wants \(i'
  1571.  
  1572.     s/[\200]/C\\*,/g;
  1573.     s/[\201]/u\\*:/g;
  1574.     s/[\202]/e\\*'/g;
  1575.     s/[\203]/a\\*^/g;
  1576.     s/[\204]/a\\*:/g;
  1577.     s/[\205]/a\\*`/g;
  1578.     s/[\206]/a\\*o/g;
  1579.     s/[\207]/c\\*,/g;
  1580.     s/[\210]/e\\*^/g;
  1581.     s/[\211]/e\\*:/g;
  1582.     s/[\212]/e\\*`/g;
  1583.     s/[\213]/i\\*:/g;
  1584.     s/[\214]/i\\*^/g;
  1585.     s/[\215]/i\\*`/g;
  1586.     s/[\216]/A\\*:/g;
  1587.     s/[\217]/A\\*o/g;
  1588.     s/[\220]/E\\*'/g;
  1589.     s/[\221]//g;      # Can't make out what this is supposed to be.
  1590.     s/[\222]//g;      # Ditto
  1591.     s/[\223]/o\\*^/g;
  1592.     s/[\224]/o\\*:/g;
  1593.     s/[\225]/o\\*`/g;
  1594.     s/[\226]/u\\*^/g;
  1595.     s/[\227]/u\\*`/g;
  1596.     s/[\230]/y\\*:/g;
  1597.     s/[\231]/o\\*:/g;
  1598.     s/[\232]/u\\*:/g;
  1599.     s/[\233]/\\\(ct/g;
  1600.     s/[\234]/\\\(L-/g;
  1601.     s/[\235]/\\\(Y=/g;
  1602.     s/[\236]//g;      # should handle this
  1603.     s/[\237]//g;      # and this
  1604.     s/[\240]/a\\*'/g;
  1605.     s/[\241]/i\\*'/g;
  1606.     s/[\242]/o\\*'/g;
  1607.     s/[\243]/u\\*'/g;
  1608.     s/[\244]/n\\*~/g;
  1609.     s/[\245]/N\\*~/g;
  1610.     s/[\246]/\\\(a_/g;
  1611.     s/[\247]/\\\(o_/g;
  1612.  
  1613.     s/[\250]/\\*?/g;
  1614.     s/[\251]//g;
  1615.     s/[\252]/\\\(no/g;
  1616.     s/[\253]/\\\(12/g;
  1617.     s/[\254]/\\\(14/g;
  1618.     s/[\255]/\\*!/g;
  1619.     s/[\256]/\\\(<</g;
  1620.     s/[\257]/\\\(>>/g;
  1621.  
  1622.    s/[\360]/\\\(==/g;
  1623.     s/[\361]/\\\(+-/g;
  1624.     s/[\362]/\\\(>=/g;
  1625.     s/[\363]/\\\(<=/g;
  1626.     s/[\364]//g;
  1627.     s/[\365]//g;
  1628.     s/[\366]/\\\(di/g;
  1629.     s/[\367]/\\\(~~/g;
  1630.  
  1631.     s/[\373]/\\\(sr/g;
  1632.  
  1633.     # I'm taking a guess that \376 is supposed to be the R set.
  1634.     s/[\376]/\\\(Re/g;
  1635.   }
  1636.  
  1637.   return $_;
  1638. }
  1639.  
  1640.